package com.pearadmin.pro.modules.gen.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pearadmin.pro.common.constant.GenerateConstant;
import com.pearadmin.pro.common.constant.SystemConstant;
import com.pearadmin.pro.common.tools.core.SequenceUtil;
import com.pearadmin.pro.common.tools.core.StringUtil;
import com.pearadmin.pro.common.web.base.page.PageResponse;
import com.pearadmin.pro.common.web.base.page.Pageable;
import com.pearadmin.pro.common.web.exception.base.BusinessException;
import com.pearadmin.pro.modules.gen.domain.GenTable;
import com.pearadmin.pro.modules.gen.domain.GenTableColumn;
import com.pearadmin.pro.modules.gen.param.TableRequest;
import com.pearadmin.pro.modules.gen.repository.GenTableColumnRepository;
import com.pearadmin.pro.modules.gen.repository.GenTableRepository;
import com.pearadmin.pro.modules.gen.service.GenTableService;

import com.pearadmin.pro.modules.gen.tools.GenTemplateUtil;
import com.pearadmin.pro.modules.gen.tools.GenUtil;

import org.apache.commons.io.FileUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;


@Service
public class GenTableServiceImpl implements GenTableService {

    @Autowired
    private GenTableRepository genTableRepository;

    @Autowired
    private GenTableColumnRepository genTableColumnRepository;


    /**
     * 获取代码生成地址
     *
     * @param table    业务表信息
     * @param template 模板文件路径
     * @return 生成地址
     */
    public static String getGenPath(GenTable table, String template) {
        String genPath = table.getGenPath();
        if (StringUtil.equals(genPath, SystemConstant.SLASH)) {
            return System.getProperty("user.dir") + File.separator + "src" + File.separator + GenTemplateUtil.getFileName(template, table);
        }
        return genPath + File.separator + GenTemplateUtil.getFileName(template, table);
    }


    /**
     * 查询业务列表
     *
     * @param request 业务信息
     * @return
     */
    @Override
    public PageResponse<GenTable> selectDbTableList(TableRequest request) {
        return Pageable.of(request,(()-> genTableRepository.selectDbTableList(request)));

    }

    /**
     * 设置主子表信息
     *
     * @param table 业务表信息
     */
    public void setSubTable(GenTable table) {
        String subTableName = table.getSubTableName();
        if (StringUtil.isNotEmpty(subTableName)) {
            table.setSubTable(genTableRepository.selectGenTableByName(subTableName));
        }
    }

    /**
     * 设置主键列信息
     *
     * @param table 业务表信息
     */
    public void setPkColumn(GenTable table) {
        for (GenTableColumn column : table.getColumns()) {
            if (column.isPk()) {
                table.setPkColumn(column);
                break;
            }
        }
        if (StringUtil.isNull(table.getPkColumn())) {
            table.setPkColumn(table.getColumns().get(0));
        }
        if (GenerateConstant.TPL_SUB.equals(table.getTplCategory())) {
            for (GenTableColumn column : table.getSubTable().getColumns()) {
                if (column.isPk()) {
                    table.getSubTable().setPkColumn(column);
                    break;
                }
            }
            if (StringUtil.isNull(table.getSubTable().getPkColumn())) {
                table.getSubTable().setPkColumn(table.getSubTable().getColumns().get(0));
            }
        }
    }

    /**
     * 查询据库列表
     *
     * @param tableNames 表名称组
     * @return 数据库表集合
     */
    @Override
    public List<GenTable> selectDbTableListByNames(String[] tableNames) {
        return genTableRepository.selectDbTableListByNames(tableNames);
    }

    /**
     * 预览代码
     *
     * @param tableId 表编号
     * @return 预览数据列表
     */
    @Override
    public Map<String, String> previewCode(String tableId) {
        Map<String,String> dataMap = new LinkedHashMap<>();
        GenTable table = genTableRepository.selectGenTableById(tableId);
        setSubTable(table);
        setPkColumn(table);
        GenTemplateUtil.initVelocity();
        VelocityContext context = GenTemplateUtil.prepareContext(table);
        List<String> templates = GenTemplateUtil.getTemplateList(table.getTplCategory());
        for(String template : templates) {
            StringWriter sw = new StringWriter();
            Template tpl = Velocity.getTemplate(template, SystemConstant.UTF8);
            tpl.merge(context,sw);
            dataMap.put(template,sw.toString());
        }
        return dataMap;
    }

    @Override
    public void generatorCode(String tableName) {
        GenTable table = genTableRepository.selectGenTableByName(tableName);
        setSubTable(table);
        setPkColumn(table);

        GenTemplateUtil.initVelocity();

        VelocityContext context = GenTemplateUtil.prepareContext(table);

        List<String> templates = GenTemplateUtil.getTemplateList(table.getTplCategory());

        for(String template : templates) {
            if(!StringUtil.contains(template,"sql.vm")) {
                StringWriter sw = new StringWriter();
                Template tpl = Velocity.getTemplate(template, SystemConstant.UTF8);
                tpl.merge(context,sw);
                try {
                    String path = getGenPath(table, template);
                    FileUtils.writeStringToFile(new File(path), sw.toString(), SystemConstant.UTF8);
                } catch (IOException e) {
                    throw new BusinessException("渲染模板失败，表名：" + table.getTableName());
                }
            }
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importGenTable(List<GenTable> tableList) {
        for(GenTable table : tableList) {
            GenUtil.initTable(table);
            int row = genTableRepository.insertGenTable(table);
            if (row > 0 ) {
                List<GenTableColumn> genTableColumns = genTableColumnRepository.selectDbTableColumnsByName(table.getTableName());
                for(GenTableColumn column : genTableColumns) {
                    column.setColumnId(SequenceUtil.makeStringId());;
                    GenUtil.initColumnField(column,table);

                    genTableColumnRepository.insertGenTableColumn(column);
                }
            }
        }
    }

    /**
     * 查询业务列表
     *
     * @param request 业务信息
     * @return 业务集合
     */
    @Override
    public PageResponse<GenTable> selectGenTableList(TableRequest request) {
        return Pageable.of(request,()-> genTableRepository.selectGenTableList(request));
    }

    @Override
    public void validateEdit(GenTable genTable) {
        if(GenerateConstant.TPL_TREE.equals(genTable.getTplCategory())){
            if (StringUtil.isEmpty(genTable.getTreeCode())){
                throw  new BusinessException("树编码字段不能为空");
            } else if (StringUtil.isEmpty(genTable.getTreeCode())){
                throw  new BusinessException("树父编码字段不能为空");
            }
        }else if (GenerateConstant.TPL_SUB.equals(genTable.getTplCategory())) {
            if (StringUtil.isEmpty(genTable.getSubTableName())) {
                throw new BusinessException("关联子表的表名不能为空");
            }else if (StringUtil.isEmpty(genTable.getSubTableFkName())){
                throw new BusinessException("子表关联的外键名不能为空");
            }
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateGenTable(GenTable genTable) {
        int row = genTableRepository.updateGenTable(genTable);
        if(row > 0 ) {
            for(GenTableColumn genTableColumn: genTable.getColumns()){
                genTableColumnRepository.updateGenTableColumn(genTableColumn);
            }
        }
    }


}
